#ifndef __CELESTIALSYSTEM_H__
#define __CELESTIALSYSTEM_H__

#include "../D3DRenderer/D3DRenderer.h"
using namespace Renderer;

namespace Sphericubic
{
	//--------------------------------------------------------------------
	//--------------------------------------------------------------------
	//--------------------------------------------------------------------

	// Any spacial object.

	class CelestialObject;
	typedef vector<CelestialObject*>		CelestialObjectPtrVec;
	typedef map<DataKey, CelestialObject*>	CelestialObjectPtrMap;

	class CelestialObject : public Renderable
	{
	public:
		enum EType
		{
			EType_UNKNOWN,
			EType_AXE,
			EType_GALAXY,
			EType_SYSTEM,
			EType_STAR,
			EType_PLANET,
			EType_COMET,
			EType_ASTEROID,
			EType_COUNT // last enum member
		};

		enum ELevelOfDetail
		{
			ELevelOfDetail_UNKNOWN,
			ELevelOfDetail_POINT,
			ELevelOfDetail_BILLBOARD,
			ELevelOfDetail_UNTEXTUREDSIMPLEMESH,
			ELevelOfDetail_TEXTUREDSIMPLEMESH,
			ELevelOfDetail_DETAILMESH,
			ELevelOfDetail_COUNT // last enum member
		};

	public:
		CelestialObject(const EType& _eType);
		virtual ~CelestialObject();

		const EType& GetType() const;

		void SetLevelOfDetail(const ELevelOfDetail& _eELevelOfDetail);
		const ELevelOfDetail& GetLevelOfDetail() const;

		virtual void Update(const float& _fTimeSpeed) = 0;
		virtual const Matrix& GetWorldMatrix() const = 0;
		virtual void SetParent(CelestialObject* _pParent) = 0;
		virtual CelestialObject* GetParent() const = 0;
		virtual void AddChild(CelestialObject* _pChild) = 0;
		virtual void RemoveChild(CelestialObject* _pChild) = 0;
		virtual const CelestialObjectPtrVec& GetChildren() const = 0;
		virtual void GetWorldAABB(Vector3& _oTopRightBack, Vector3& _oBottomLeftFront) const = 0;
		virtual const float& GetMaxSize() const = 0;

		virtual void GetDepthRadiusModifiers(float& _fZNear, float& _fZFar) const;

	protected:
		EType			m_eType;
		ELevelOfDetail	m_eLevelOfDetail;
	};

	//--------------------------------------------------------------------
	//--------------------------------------------------------------------
	//--------------------------------------------------------------------

	// Spacial with a repeating revolution around an axis (star, planet, comet, satellite, etc.).

	class OrbitingObject : public CelestialObject
	{
	public:
		OrbitingObject(const EType& _eType);
		virtual ~OrbitingObject();

		virtual const Matrix& GetWorldTransform() const;

		virtual void Update(const float& _fTimeSpeed);
		virtual const Matrix& GetWorldMatrix() const;
		virtual void SetParent(CelestialObject* _pParent);
		virtual CelestialObject* GetParent() const;
		virtual void AddChild(CelestialObject* _pChild);
		virtual void RemoveChild(CelestialObject* _pChild);
		virtual const CelestialObjectPtrVec& GetChildren() const;
		virtual void GetWorldAABB(Vector3& _oTopRightBack, Vector3& _oBottomLeftFront) const;
		virtual const float& GetMaxSize() const;

		// object rotation axis around its parent.
		virtual void SetRotationAxisToParent(const Vector3& _oAxis);

		// object self rotation axis.
		virtual void SetRotationAxisToSelf(const Vector3& _oAxis);

		// object rotation speed in degree around its parent.
		virtual void SetRotationSpeedToParent(const float& _fSpeed);

		// object self rotation speed in degree.
		virtual void SetRotationSpeedToSelf(const float& _fSpeed);

		//
		virtual void SetDistanceToParent(const float& _fDistance);

	protected:
		CelestialObjectPtrVec	m_vChildren;
		Matrix					m_oWorld;
		Vector3					m_oAxisToParent;
		Vector3					m_oAxisToSelf;
		Vector3					m_oBoundingSize;
		CelestialObject*		m_pParent;
		float					m_fSpeedToParent;
		float					m_fSpeedToSelf;
		float					m_fCurrentRotToParent;
		float					m_fCurrentRotToSelf;
		float					m_fDistanceToParent;
		float					m_fMaxSize;
	};

	//--------------------------------------------------------------------
	//--------------------------------------------------------------------
	//--------------------------------------------------------------------

	class ViewManager
	{
	public:
		ViewManager();
		virtual ~ViewManager();

		virtual void SetRenderer(D3DRenderer* _pRenderer);
		virtual void SetCameraPos(Vector3* _pCameraPos);
		virtual void SetPixelRatio(const float& _fPixelRatio);

		virtual void Update(CelestialObject& _rCelestialObject);

	protected:
		virtual float GetObjectPixelSize(const CelestialObject& _rCelestialObject, float* _pfZNear = NULL, float* _pfZFar = NULL) const;
		virtual void DetermineObjectLevelOfDetail(CelestialObject& _rCelestialObject, float* _pfZNear = NULL, float* _pfZFar = NULL) const;
		void Traverse(CelestialObject& _rCelestialObject);

	protected:
		Vector3			m_oCamFrontDir;
		Vector3			m_oCamRightDir;
		Vector3			m_oCamUpDir;
		D3DRenderer*	m_pRenderer;
		Vector3*		m_pCameraPos;
		float			m_fPixelRatio;
	};
}

#endif // __CELESTIALSYSTEM_H__